package io.chance.receiverlei.channel;

import lrq.common.MyLog;
import org.apache.log4j.Logger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 处理粘包拆包
 *
 * @author gislin
 */
public class MessageDecode extends FrameDecoder {
    private static Logger log;
    public static HashMap<Object, AtomicInteger> errorDecodeTimes = new HashMap<>();//丢包丢帧导致解析故障多次后，主动断开清空buffer

    @Override
    protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) {

        if (log == null) {
            log = MyLog.getLogger("Decoder");
        }

        try {
            //从站编号加上数据长度，必须有3位
            if (buffer.readableBytes() < 3) {
                log.info("数据长度不够");
                return null;
            }

            buffer.markReaderIndex();
            int readIndex = buffer.readerIndex();
            byte[] mnByte = new byte[1];
            buffer.getBytes(readIndex, mnByte);

            byte[] dataLengthByte = new byte[1];
            buffer.getBytes(readIndex + 2, dataLengthByte);

//            if (dataLengthByte[0] == 0) {
//                // 如果长度为0 说明是心跳包
//                ChannelBuffer channelBuffer = buffer.readBytes(3);
////                int mn = ByteUnit.ConvertByteToInt8(mnByte[0]);
//                return channelBuffer;
//            }
//
//            if ((dataLengthByte[0] & 0xff) < 0) {
//                String msg = getMsgString(buffer);
//                log.error("长度为负数:" + msg);
//                buffer.clear();
//                channel.close();
//                return null;
//            }
            int expectDataLength = 1 + 1 + 1 + (dataLengthByte[0] & 0xff) + 2;//1位从站编号，1位功能码，1位数据长度，n位数据，2位校验位
            if (buffer.readableBytes() < expectDataLength) {
                //获取的数据长度和期望的长度不匹配，说明数据还没有接受完整，返回null等待数据
                log.info("数据长度不够，期望：" + expectDataLength + "，实际：" + buffer.readableBytes());
                buffer.resetReaderIndex();

                if (!errorDecodeTimes.containsKey(channel)) {
                    errorDecodeTimes.put(channel, new AtomicInteger(0));
                }
                int errorTimes = errorDecodeTimes.get(channel).incrementAndGet();
                if (errorTimes > 10) {
                    log.info("数据粘包错误次数过多，" + ((InetSocketAddress) channel.getRemoteAddress()).getHostString());
                    errorDecodeTimes.remove(channel);
                    buffer.clear();
                    channel.close();
                }
                return null;
            }
            else {
                ChannelBuffer channelBuffer = buffer.readBytes(expectDataLength);
                return channelBuffer;
            }
        }
        catch (Exception e) {
            log.error("报文粘拆包处理出错:" + getMsgString(buffer), e);
            return null;
        }
    }

    private String getMsgString(ChannelBuffer buffer) {
        byte[] tempByte = new byte[buffer.readableBytes()];
        buffer.getBytes(0, tempByte, 0, buffer.readableBytes());

        return bytes2Hex(tempByte);
    }

    public static String bytes2Hex(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (byte aByte : bytes) {
            sb.append(String.format("%02X", aByte));
        }
        return sb.toString().trim();
    }

    public static byte[] hexToBytes(String hex) {
        int m = 0, n = 0;
        int byteLen = hex.length() / 2; // 每两个字符描述一个字节
        byte[] ret = new byte[byteLen];
        for (int i = 0; i < byteLen; i++) {
            m = i * 2 + 1;
            n = m + 1;
            int intVal = Integer.decode("0x" + hex.substring(i * 2, m) + hex.substring(m, n));
            ret[i] = (byte) intVal;
        }
        return ret;
    }

    public static byte[] int2Bytes(int i) {
        byte[] arr = new byte[4];
        arr[0] = (byte) i;
        arr[1] = (byte) (i >> 8);
        arr[2] = (byte) (i >> 16);
        arr[3] = (byte) (i >> 24);
        return arr;
    }

    public static int bytes2Int(byte[] bytes) {
        try {
            return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
//        int i0 = bytes[0];
//        int i1 = (bytes[1] & 0xFF) << 8; //补字节生成32位字节
//        int i2 = (bytes[2] & 0xFF) << 16;
//        int i3 = (bytes[3] & 0xFF) << 24;
//        return i0 | i1 | i2 | i3;
    }

    public static long bytes2Long(byte[] bytes) {
        try {
            return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getLong();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}
